package engine;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * Level.java
 * Maintains/Updates Sprites contained in a single level of the game
 * 
 * @author Niel Lebeck, Connor Gordon
 * 
 */
public abstract class Level {
    private List<Sprite> mySpriteList;
    private List<Character> myCharacterList;

    /**
     * Initializes Sprite and Character lists
     */
    public Level () {
        mySpriteList = new ArrayList<Sprite>();
        myCharacterList = new ArrayList<Character>();
    }

    /**
     * Returns unmodifiable version of all sprites contained in the level
     * 
     * @return list of contained sprites
     */
    public Iterable<Sprite> getSpriteList () {
        return Collections.unmodifiableList(mySpriteList);
    }

    /**
     * Adds certain sprite to the level
     * 
     * @param s Sprite being added
     */
    public void addSprite (Sprite s) {
        mySpriteList.add(s);
        if (s instanceof Character) {
            myCharacterList.add((Character) s);
        }
    }

    /**
     * Removes specified sprite from the level
     * 
     * @param s Sprite to be removed
     */
    public void removeSprite (Sprite s) {
        mySpriteList.remove(s);
        if (s instanceof Character) {
            myCharacterList.remove(s);
        }
    }

    /**
     * Propagates KeyEvents to Player classes - presses
     * 
     * @param k KeyEvent
     */
    public void keyPressed (KeyEvent k) {
        for (Character c : myCharacterList) {
            if (c instanceof Player) {
                ((Player) c).keyPressed(k);
            }
        }
    }

    /**
     * Propagates KeyEvents to Player classes - releases
     * 
     * @param k KeyEvent propogated
     */
    public void keyReleased (KeyEvent k) {
        for (Character c : myCharacterList) {
            if (c instanceof Player) {
                ((Player) c).keyReleased(k);
            }
        }
    }

    /**
     * Calls the update() method of all the characters in the level
     */
    public void updateCharacters () {
        List<Character> removalList = new ArrayList<Character>();
        for (Character c : myCharacterList) {
            c.update(this);
            if (c.shouldRemove()) {
                removalList.add(c);
            }
        }
        for (Character cr : removalList) {
            myCharacterList.remove(cr);
            mySpriteList.remove(cr);
        }

    }

    /**
     * Paints each sprite in the level
     * 
     * @param g Graphics Drawing Object
     * @param offsetX relative point of origin- x
     * @param offsetY relative point of origin -y
     */
    public void paintSprites (Graphics g, int offsetX, int offsetY) {
        for (Sprite s : mySpriteList) {
            s.paint(g, offsetX, offsetY);
        }
    }

    /**
     * Paints background of window
     * 
     * @param g Graphics drawing objecct
     */
    public abstract void paintBackground (Graphics g);

    /**
     * Resets level to beginning
     */
    public abstract void reset ();

    /**
     * Returns current PlayState of the level
     * 
     * @return current PlayState
     */
    public abstract PlayState getPlayState ();
}
